package com.yonyou.le.unattended.websocket.hardware;

import java.io.IOException;
import java.util.List;

import net.sf.json.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.google.gson.Gson;
import com.yonyou.le.unattended.cache.DeviceCacheManager;
import com.yonyou.le.unattended.cache.MonitorCacheManager;
import com.yonyou.le.unattended.cache.MonitorCacheTypeEnum;
import com.yonyou.le.unattended.cache.entity.DeviceData;
import com.yonyou.le.unattended.delivery.entity.DevGroupParamVO;
import com.yonyou.le.unattended.delivery.entity.OperatPointParamVO;
import com.yonyou.le.unattended.delivery.enumeration.DevicePositionEnum;
import com.yonyou.le.unattended.delivery.enumeration.DevtypeEnum;
import com.yonyou.le.unattended.entity.meta.CarInfoData;
import com.yonyou.le.unattended.util.ProConstant;
import com.yonyou.le.unattended.websocket.MonitorUtils;
import com.yonyou.le.unattended.websocket.MsgTypeEnum;


/**
 * 硬件适配器指令与服务器建立的websocket连接
 * @author weijw
 *
 */
public class HardwareInstructWSHandler extends TextWebSocketHandler {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private DeviceCacheManager deviceCacheManager;
	private MonitorCacheManager monitorCacheManager;
	private ProConstant proConstant;
	/**
	 * 硬件消息内容
	 */
	private final String HARDWARE_MSG_INFO="info";
	/**
	 * 如果是衡器，则用重量信息
	 */
	private final String HARDWARE_MSG_WEIGHT="weight";
	/**
	 * 如果是红外，则有连接信息
	 */
	private final String HARDWARE_MSG_RED="isConnect";
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		logger.info("ConnectionEstablished sessionID="+session.getId());
		WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
		deviceCacheManager = (DeviceCacheManager) context.getBean("deviceCacheManager");
		monitorCacheManager = (MonitorCacheManager) context.getBean("monitorCacheManager");
	}

	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		//logger.info("threshold: " +proConstant.weight_threshold);	
		WSConCache.putSession(session);
		//获取适配器传输的数据
		Gson gs = new Gson();
		HardwareInfoEntity data = gs.fromJson((String)message.getPayload(), HardwareInfoEntity.class);
		//根据设备编码找到对应的作用点等基本信息
		DeviceData deviceData = deviceCacheManager.getDeviceData(data.getDeviceCode(),DeviceData.class);
		if(deviceData!=null){
			if(deviceData.getDeviceParamVO() == null){//衡器信息
				this.updateWeight(deviceData, data);
			}else{//普通设备信息-红外
				this.updateDevice(deviceData, data);
			}
		}else{
			logger.error("ERROR,没有对应的设备信息……");
		}

		//根据设备类型进行相应的逻辑操作
		//考虑设备间的联动操作（是否需要缓存设备的状态）TODO
		
	}

	

	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		//發生TIMEOUTEXCEPTION時需要重新試連接 TODO
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
		WSConCache.removeSession(session.getId());
	}

	@Override
	public boolean supportsPartialMessages() {
		return false;
	}
	/**
	 * 
	 * @param deviceData
	 * @param data
	 */
	private void updateDevice(DeviceData deviceData, HardwareInfoEntity data){
		List<OperatPointParamVO> operatPointParamVOs = deviceData.getOperatPointParamVOs();
		DevGroupParamVO devGroupParamVO = deviceData.getDevGroupParamVO();//设备类型
		if(operatPointParamVOs!=null){
			if(operatPointParamVOs.size()!=1){
				logger.error("write to cache of meanpk/devicecode = "+data.getDeviceCode() +"error,exist more than 1 operatePoint!");
			}else{					
				OperatPointParamVO operatPointParamVO = operatPointParamVOs.get(0);
				String opcode=operatPointParamVO.getHcopercode();
				JSONObject jo = JSONObject.fromObject(data);
				String isConnected=String.valueOf(jo.getJSONObject(HARDWARE_MSG_INFO).get(HARDWARE_MSG_RED));
				if(devGroupParamVO.getHfdevtype()!=null){
					if(devGroupParamVO.getHfdevtype().equals(DevtypeEnum.FDIEnum.getIndex())){//红外
						//logger.info("作业点: " + operatPointParamVO.getHcopercode()+"红外: "+data.getDeviceCode()+" is " + isConnected);	
						//更新作业点重量信息
						String pos=operatPointParamVO.getBcdeviceposition();
						if(StringUtils.isNotBlank(pos)){
							if(pos.equals(DevicePositionEnum.WEIGH_FRONT.getIndex()+"")){//pos是String ,getIndex()是int
								logger.info("作业点: " + operatPointParamVO.getHcopername()+" UPDATE 红外编码: "+data.getDeviceCode()+" is " + isConnected);	
								monitorCacheManager.updateRedA(opcode, isConnected);
							}else{
								logger.info("作业点: " + operatPointParamVO.getHcopername()+" UPDATE 红外编码: "+data.getDeviceCode()+" is " + isConnected);	
								monitorCacheManager.updateRedB(opcode, isConnected);
							}

						}else{
							logger.error("红外"+data.getDeviceCode()+"没有设置对应的位置！磅前 or 磅后");
						}
						
					}else{//其他设备
						logger.error("未知设备类型：" +devGroupParamVO.getHfdevtype() + "设备编码："+data.getDeviceCode());
					}
				}else{
					logger.error("ERROR,"+data.getDeviceCode()+"未知设备类型");
				}
			}
		}else{
			logger.error("ERROR,"+data.getDeviceCode()+"该设备没有在任何作业点下");
		}

	}
	/**
	 * 更新重量
	 * @param deviceData
	 * @param data
	 */
	private void updateWeight(DeviceData deviceData, HardwareInfoEntity data) {
		List<OperatPointParamVO> operatPointParamVOs = deviceData.getOperatPointParamVOs();
		if(operatPointParamVOs!=null){
			if(operatPointParamVOs.size()!=1){
				logger.error("write to cache of meanpk/devicecode = "+data.getDeviceCode() +" error,exist more than 1 operatePoint!");
			}else{					
				OperatPointParamVO operatPointParamVO = operatPointParamVOs.get(0);
				
				String opcode=operatPointParamVO.getHcopercode();
				JSONObject jo = JSONObject.fromObject(data);
				String weight=String.valueOf(jo.getJSONObject(HARDWARE_MSG_INFO).get(HARDWARE_MSG_WEIGHT));
				logger.info("作业点: " + operatPointParamVO.getHcopername()+ "  重量变为: " + weight);	
				//更新作业点重量信息
				monitorCacheManager.updateCurWeight(opcode,weight);
				
				//根据重量修改车辆状态
				this.updateStatus(weight, opcode);
				try {
					//前台更新作业点重量信息
					MonitorUtils.sendMessage(MsgTypeEnum.WS_TYPE_WEIGHT.getName(), opcode,weight);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}else{
			logger.error("ERROR,"+data.getDeviceCode()+"该设备没有在任何作业点下");
		}
		
	}
	/**
	 * 根据重量修改车辆状态 通知给监控
	 * @param weight
	 * @param opcode
	 */
	private void updateStatus(String weight,String opcode){
		Integer status = monitorCacheManager.getCacheData(MonitorCacheTypeEnum.PICTURE_STATUS, opcode, Integer.class);
		if(weight!=null && status != null){
			if(Double.valueOf(weight) > proConstant.weight_threshold && status == 1){ //车辆上磅，有重量时修改图片状态
				monitorCacheManager.updatePictureStatus(opcode, 2);
				try {
					MonitorUtils.sendMessage(MsgTypeEnum.WS_TYPE_CARSTATUS.getName(), opcode, "2");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}else if(Double.valueOf(weight) == 0 && status == 3){//车辆下磅后，当重量变为0时，修改图片状态
				monitorCacheManager.updatePictureStatus(opcode, 0);
				try {
					MonitorUtils.sendMessage(MsgTypeEnum.WS_TYPE_CARSTATUS.getName(), opcode, "0");
					MonitorUtils.sendMessage(MsgTypeEnum.WS_TYPE_CARINFO.getName(), opcode,new Gson().toJson(new CarInfoData()));
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public ProConstant getProConstant() {
		return proConstant;
	}

	public void setProConstant(ProConstant proConstant) {
		this.proConstant = proConstant;
	}
	
}
